Skip to content

开启Web站点的http2协议 ​

目前国内许多主流的站点都开始开启了H2协议,http2协议的优势不言而喻,能加快网络传输效率,提升Web服务的访问效率。 那么如何开启http2协议呢,本文就以 Nginx 搭建的站点为例,详细说一下怎么一步步实现支持H2协议的 Web站点。

相关背景 ​

在当前无论是国内还是国外,相当多的主流网站或APP都开始支持HTTP2协议了。 以下测试了淘宝、抖音、github三家站点,它们都开启了HTTP2协议了。

Alt text

目前 客户端浏览器对 H2协议的支持情况怎么样呢?

Alt text

从上图可以看出,除了IE11以下的浏览器不支持 Http2 协议,几乎所有的浏览器都支持了,将近 97% 的支持率说明没有什么兼容性问题了。

H2协议简介 ​

什么是http2协议?

http/2 is a replacement for how http is expressed “on the wire.” It is not a ground-up rewrite of the protocol; http methods, status codes and semantics are the same, and it should be possible to use the same APIs as http/1.x (possibly with some small additions) to represent the protocol.

从官网的描述中,我们可以看出:

  • 对1.x协议语意的完全兼容

2.0协议是在1.x基础上的升级而不是重写,1.x协议的方法,状态及api在2.0协议里是一样的

The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site.

  • 主要目标是提升性能

让终端用户使用网络服务,访问网络资源,没有那么高的延迟,能及时给出请求的响应内容,优化性能。 在一个TCP链接中,就能够完成终端和站点之间的通信。

H2优化的内容有很多,我们就不一一展开了,文末有相关的链接,感兴趣的话可以点开细读。

  • 二进制分帧(Binary Format)设计
  • 多路复用 (Multiplexing) / 连接共享
  • 头部压缩(Header Compression)
  • 服务端推送(Server Push)
  • 。。。。。。

接下来我们进入开启http2协议的流程中。

整体的流程 ​

必备的条件 ​

开启H2协议,需要一下必备条件:

  • 先有个域名(需要购买了,有很多便宜的几块钱一年的)
  • 获得 SSL 证书(如何获得下面介绍)
  • Nginx的版本高于 1.9.5(其它Web服务器软件如Apache,需要自行查看一下)
  • 开启相关的 Nginx 的模块 和 配置

整体流程 ​

整个流程如下:

  1. 先获得 SSL 证书
  2. 使用 SSL证书,开启 HTTPS协议
  3. 配置 H2 协议
  4. 重新载入配置,启动 Web server
  5. 测试效果

Alt text

获得SSL证书 ​

如何获得 SSL 证书呢?

有多种方式,看个人的需求。如果是工作上的Web服务,有真实的消费用户,那还是购买正规的SSL证书比较好。 SSL证书的种类也是多种多样的,当然价格越高支持的特性越多,提供的安全性会更好些。以下是国内某云厂商提供的各种 SSL 证书的规格说明,用以满足不同场景下的业务需求。

Alt text

本文的目的是研究和学习,咱们就申请一个免费的 SSL 证书,来做一下试验。 获得免费证书的途径也有很多的,许多国内外的云厂家(阿里、腾讯、华为、亚马逊等)都提供免费的SSL证书的。 在文末的链接中,提供了三个获得免费SSL证书的网址,需要的小伙伴们自取。

一般在申请的过程中,需要填写一下您的域名、个人联系方式,很简单的。

Alt text

填写完成后,大约 2 ~ 3 分钟后,就会收到证书通知,产生下面的一条记录。 展示是免费的SSL证书,到期时间,并提供证书的下载入口。

Alt text

我们点击“下载”,选择 Nginx 格式的证书文件。

Alt text

我们将下载后的证书文件保存到本地磁盘,其中包括证书以及秘钥两个文件。

Alt text

接下来,我们将证书文件上传到服务器的 Nginx 目录下面

上传SSL证书 ​

将本地的证书上传到服务器有多种方式,包括rz、FTP、SFTP等等,我们这里使用 rz 上传。 使用 rz 上传前,要确保先安装了 lrzsz 这个工具。 lrzsz 这个工具专门用于远程传输文件的,其中 rz 是从本地上传文件到服务器, sz 是从远程服务下载文件到本地。如果本地使用的是 苹果Mac系统的电脑,远程服务器是 Linux 系统,Shell 用的是 iTerm2,可以参照下面的方式配置一下 rz 的环境:

配置 rz、sz上传下载 ​

  • 在远程服务器(centos)上安装lrzsz:yum install lrzsz
  • 在本地的Mac 系统中安装 lrzsz工具:brew install lrzsz
  • 按照下图所示,设置一下iTerm2 的触发器,目的是在接收或发送文件时能和系统的文件管理器交互

Alt text

具体填写的内容:

Regular ExpressionActionParameters
\*\*B0100 Run Silent Coprocess/usr/local/bin/iterm2-send-zmodem.sh
\*\*B00000000000000Run Silent Coprocess/usr/local/bin/iterm2-recv-zmodem.sh

这样当我们在 iTerm2 的 shell 中执行 rz 上传命令时,就会弹出系统的文件管理窗体了,就可以选择要上传的证书文件了。

关于 iterm2-send-zmodem.sh 和 iterm2-recv-zmodem.sh 两个 shell 脚本的文件内容,需要手动创建到指定的 /usr/local/bin 目录下

iterm2-send-zmodem.sh,通知 iTerm2 在 发送文件时,弹出“选择要发送文件”的系统窗口

sh
#!/bin/bash
# iterm2-send-zmodem.sh 文件的内容:

osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
	FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
else
	FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
fi
if [[ $FILE = "" ]]; then
	echo Cancelled.
	# Send ZModem cancel
	echo -e \\x18\\x18\\x18\\x18\\x18
	sleep 1
	echo
	echo \# Cancelled transfer
else
	/usr/local/bin/sz "$FILE" -e -b
	sleep 1
	echo
	echo \# Received $FILE
fi
#!/bin/bash
# iterm2-send-zmodem.sh 文件的内容:

osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
	FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
else
	FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
fi
if [[ $FILE = "" ]]; then
	echo Cancelled.
	# Send ZModem cancel
	echo -e \\x18\\x18\\x18\\x18\\x18
	sleep 1
	echo
	echo \# Cancelled transfer
else
	/usr/local/bin/sz "$FILE" -e -b
	sleep 1
	echo
	echo \# Received $FILE
fi

iterm2-recv-zmodem.sh,通知 iTerm2 在接收文件时,弹出“选择要接收的目录”的系统窗口

sh
#!/bin/bash
# iterm2-recv-zmodem.sh 文件的内容:

osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
	FILE=$(osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
else
	FILE=$(osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
fi

if [[ $FILE = "" ]]; then
	echo Cancelled.
	# Send ZModem cancel
	echo -e \\x18\\x18\\x18\\x18\\x18
	sleep 1
	echo
	echo \# Cancelled transfer
else
	cd "$FILE"
	/usr/local/bin/rz -E -e -b --bufsize 4096
	sleep 1
	echo
	echo
	echo \# Sent \-\> $FILE
fi
#!/bin/bash
# iterm2-recv-zmodem.sh 文件的内容:

osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
	FILE=$(osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
else
	FILE=$(osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
fi

if [[ $FILE = "" ]]; then
	echo Cancelled.
	# Send ZModem cancel
	echo -e \\x18\\x18\\x18\\x18\\x18
	sleep 1
	echo
	echo \# Cancelled transfer
else
	cd "$FILE"
	/usr/local/bin/rz -E -e -b --bufsize 4096
	sleep 1
	echo
	echo
	echo \# Sent \-\> $FILE
fi

上传到服务器 ​

我们登录到远程服务器,进入到Nginx目录下面。

Alt text

  1. 创建一个 cert 目录,用于存放我们刚才下载到本地的 SSL 证书
sh
# 进入到Nginx的配置目录
cd /etc/nginx
# 创建 cert 目录
mkdir cert
# 进入到 cert 目录
cd cert
# 在服务器上执行 rz 命令,上传 SSL 证书文件
rz
# 进入到Nginx的配置目录
cd /etc/nginx
# 创建 cert 目录
mkdir cert
# 进入到 cert 目录
cd cert
# 在服务器上执行 rz 命令,上传 SSL 证书文件
rz

Alt text

如上图所示,这样输入 rz 命令就能调出本地的 选择文件发送 的系统窗体了。 我们选择好SSL证书文件后,就会上传到服务器的指定目录(/etc/nginx/cert)下了。 接下来,我们开始配置Nginx 文件。

配置SSL证书 ​

打开 Nginx的配置文件:

sh
vi nginx.conf
vi nginx.conf

修改如下的配置,主要是配置一下证书的路径,以及域名,监听的端口号。 默认情况下,可能有防火墙的策略,需要打开 443端口的通道,以保证外部的 https请求能进入。

sh
server {
    #HTTPS的默认访问端口443。
    #如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
    listen 443 ssl;
    
    #填写证书绑定的域名
    server_name mawen.tech;

    #填写证书文件名称
    ssl_certificate cert/mawen.tech.pem;
    #填写证书私钥文件名称
    ssl_certificate_key cert/mawen.tech.key;

    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
}
server {
    #HTTPS的默认访问端口443。
    #如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
    listen 443 ssl;
    
    #填写证书绑定的域名
    server_name mawen.tech;

    #填写证书文件名称
    ssl_certificate cert/mawen.tech.pem;
    #填写证书私钥文件名称
    ssl_certificate_key cert/mawen.tech.key;

    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
}

修改完毕后,执行:wq保持一下配置nginx配置文件,重新加载一个配置

sh
nginx -s reload
nginx -s reload

刷新浏览,可以看到已经是 https 协议的地址了。

Alt text

我们可以更进一步,当访问 http 的地址时,默认转发到 https 协议的地址中,以此来保证站点的内容安全性。

sh
server {
    listen 80;
    #填写证书绑定的域名
    server_name mawen.tech;
    #将所有HTTP请求通过rewrite指令重定向到HTTPS。
    rewrite ^(.*)$ https://$host$1;
    location / {
        index index.html index.htm;
    }
}
server {
    listen 80;
    #填写证书绑定的域名
    server_name mawen.tech;
    #将所有HTTP请求通过rewrite指令重定向到HTTPS。
    rewrite ^(.*)$ https://$host$1;
    location / {
        index index.html index.htm;
    }
}

nginx.conf文件中会存在两个server {}代码段,一个是 80 端口的http请求模块,另一个是 443 端口的 https 请求模块,我们要保证 80 端口的server 代码块 放在 443 端口号的下面。 这样http 到 https的转发请求,才能正常跳转过去。

开启H2协议 ​

开启 http2协议就非常简单了,甚至在新版本的Nginx 中都会默认开启 H2的。 只要在 listen 字段后面,增加 http2的设置即可。

sh
server {
  # 对应 IP4
  listen       443 ssl http2;
  # 对应 IP6
  listen       [::]:443 ssl http2;
}
server {
  # 对应 IP4
  listen       443 ssl http2;
  # 对应 IP6
  listen       [::]:443 ssl http2;
}

这里会有两个 监听,一个对应 IP4的网络地址,另一个对应 IP6的地址。 修改完保存一下,重新加载 Nginx的配置。

sh
nginx -s reload
nginx -s reload

验证一下效果:

Alt text

如上图所示,第二请求的协议地址已经变成h2了,说明我们的修改生效了。 关于Nginx的完整配置,放在文末最后的链接中了,有需要的小伙伴可以查看。

总结 ​

本文主要讲解了如何开启站点的 http2协议,这里的关键是先要支持 https协议,因为 http2时强依赖 https的,没办法直接在 http协议中开启 H2。 所以,需要先拥有SSL证书,配置好 https协议后,才能进行开启 http2协议。 与此同时,我们也简要介绍了 http2协议的优势,如何申请SSL证书,如何上传证书文件以及修改Nginx的配置等。

相关链接 ​